package model.enemy;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.image.ImageObserver;

import model.classes.Speed;
import model.game.EnemyWave;
import model.game.Path;
import model.player.Player;


/**
 * Base class for all enemies.
 * 
 * @author alexandre.altun
 */
public abstract class AbstractEnemy implements ImageObserver {
	
	public static int ENEMY_SIZE = 10;
	public static Dimension HEALTH_BAR = new Dimension(18, 2);
	
	protected Color _colorHealthBar = new Color(0, 255, 0);
	
	protected Path _path;
	
	protected float _posX = 0;
	
	protected float _posY = 0;
	
	protected Color _color = Color.WHITE;
	
	protected Speed _speed = new Speed();
	
	protected Float _speedCoef = new Float(0.5);
	
	protected Float _speedPenalty = new Float(1);
	
	protected boolean _hasBeenOnPath = false;
	
	protected float _maxHealth = 100;
	
	protected float _health = 100;
	
	protected Player _player;
	
	protected EnemyWave _enemyWave;
	
	
	/**
	 * Class constructor.
	 * It takes the Path object to travel on and his start position on the path.
	 * 
	 * @param path
	 * @param startPos
	 */
	public AbstractEnemy(Path path, Player player, Point startPos, EnemyWave enemyWave) {
		
		_path = path;
		_posX = startPos.x;
		_posY = startPos.y;
		_player = player;
		_enemyWave = enemyWave;
	}
	
	@Override
	public boolean imageUpdate(Image arg0, int arg1, int arg2, int arg3, int arg4, int arg5) {

		return false;
	}
	
	/**
	 * Makes enemy to move.
	 * This method retrieves the new speed to take from the Path object and
	 * then updates enemy position.
	 */
	public void move() {
		
		_setSpeed(_path.getSpeed(_posX, _posY));
		
		_posX = _posX + _speed.speedX;
		_posY = _posY + _speed.speedY;
		
		boolean isOnPath = _path.isOnPath(_posX, _posY, AbstractEnemy.ENEMY_SIZE);
		
		if ( isOnPath ) {
			_hasBeenOnPath = true;
		} else if ( _hasBeenOnPath ) {
			_player.loseLive();
			restartPath();
			
		}
	}
	
	
	/**
	 * Draw enemy on the buffer.
	 * This method shouldn't be override by subclasses. If you want to change the way
	 * an enemy is drawn, just override the {@see drawEnemy} method.
	 * 
	 * If you do override this method, you would have to draw the enemy AND the health bar.
	 * 
	 * @param g
	 */
	public void draw(Graphics g) {
		
		Color c = g.getColor();
		
		_drawEnemy(g);
		_drawHealthBar(g);
		
		g.setColor(c);
	}
	
	
	/**
	 * Draw the enemy on the buffer g 
	 * 
	 * @param g
	 */
	protected void _drawEnemy(Graphics g) {
		
		g.setColor(_color);
		g.fillOval((int)_posX - (int)(AbstractEnemy.ENEMY_SIZE / 2), (int)_posY - (int)(AbstractEnemy.ENEMY_SIZE / 2), AbstractEnemy.ENEMY_SIZE, AbstractEnemy.ENEMY_SIZE);
	}
	
	
	/**
	 * Draw enemy's health bar on the buffer g
	 * 
	 * @param g
	 */
	private void _drawHealthBar(Graphics g) {
		
		int barPosX = (int)_posX - (int)(AbstractEnemy.HEALTH_BAR.width / 2);
		int barPosY = (int)_posY - (int)(AbstractEnemy.ENEMY_SIZE / 2) - 2 - AbstractEnemy.HEALTH_BAR.height;
		int barWidth = (int) (( _health / _maxHealth) * AbstractEnemy.HEALTH_BAR.width);
		
		g.setColor(_colorHealthBar);
		g.fillRect(barPosX, barPosY, barWidth, AbstractEnemy.HEALTH_BAR.height);
	}
	
	
	/**
	 * Set Enemy speed by applying speed coefficient and speed penalty
	 * to the new direction. 
	 * 
	 * @param newSpeed
	 */
	private void _setSpeed(Speed newSpeed) {
		
		_speed = newSpeed;
		_speed.speedX *= _speedCoef * _speedPenalty;
		_speed.speedY *= _speedCoef * _speedPenalty;
	}
	

	/**
	 * Restart path from beginning. 
	 * This method is called only if the enemy has traveled the whole path
	 */
	private void restartPath() {
		
		_speed = new Speed();
		Point startPos = _path.getStartPos((int)(AbstractEnemy.ENEMY_SIZE * 1.5));
		_posX = startPos.x;
		_posY = startPos.y;
		_hasBeenOnPath = false;
	}
	
	
	public Point getPosition() {
		
		return new Point((int)_posX, (int)_posY);
	}

	
	public void hit(int damage) {
		
		if ( _health > damage ) {
			_health -= damage;
		} else {
			// Enemy is dead
			_health = 0;
			_enemyWave.enemyIsDead(this);
		}
	}
	
	
	public float getHealth() {
		
		return _health;
	}
	
}
